import importlib
import inspect
from typing import Dict, Set, Any

from axiom_boot.conf.manager import Settings
from axiom_boot.di.dependency import ServiceDefinition
from axiom_boot.logging.setup import get_logger
from axiom_boot.core.exceptions import FrameworkException

logger = get_logger(__name__)


class DefinitionReader:
    """
    服务定义读取器。
    负责动态导入模块，并从中解析出由 @service 或 @controller 装饰的服务定义。
    它支持通过 @conditional_on_setting 进行条件化加载。
    """

    def _get_nested_attr(self, obj: Any, attr_path: str, default: Any = None) -> Any:
        """
        安全地获取嵌套对象的属性，仅支持双下划线路径。
        例如: _get_nested_attr(settings, 'filesystem__provider')
        """
        attributes = attr_path.split('__')
        current_obj = obj
        for attribute in attributes:
            current_obj = getattr(current_obj, attribute, None)
            if current_obj is None:
                return default
        return current_obj

    def read(self, module_names: Set[str], settings: Settings) -> Dict[str, ServiceDefinition]:
        """
        读取并解析所有指定模块中的服务定义。

        Args:
            module_names: 一个包含待处理模块名称的集合。
            settings: 应用配置实例，用于检查条件化加载。

        Returns:
            一个字典，键是服务的名称，值是对应的 `ServiceDefinition` 实例。
        """
        definitions: Dict[str, ServiceDefinition] = {}
        if not module_names:
            return definitions

        logger.info("【定义读取器】: 开始读取服务定义...")
        for module_name in module_names:
            try:
                module = importlib.import_module(module_name)
                for member_name, member in inspect.getmembers(module):
                    if not (inspect.isclass(member) or inspect.isfunction(member)):
                        continue

                    # 核心修复：确保我们只处理在本模块中定义的成员，忽略所有导入的成员。
                    # 这是解决服务名称冲突和意外处理导入函数问题的根本方法。
                    # 使用 `member.__module__ == module.__name__` 比 `inspect.getmodule` 更直接和健壮。
                    if getattr(member, '__module__', None) != module.__name__:
                        continue

                    is_service = hasattr(member, '_axiom_is_service')
                    is_controller = hasattr(member, '_axiom_is_controller')

                    if not (is_service or is_controller):
                        continue

                    # 检查 @service(condition=...)
                    condition_func = getattr(member, '_axiom_service_condition', None)
                    if condition_func and not condition_func(settings):
                        logger.warning(f"【定义读取器】: 服务 '{member.__name__}' 未被加载: @service 的条件函数返回 False。")
                        continue

                    # 检查 @conditional_on_setting(...) 列表
                    conditional_settings_list = getattr(member, '_axiom_conditional_on_setting_list', None)
                    if conditional_settings_list:
                        all_conditions_met = True
                        for condition in conditional_settings_list:
                            key, expected_value, match_if_present, negate = condition
                            actual_value = self._get_nested_attr(settings, key, None)

                            condition_met = False
                            if match_if_present:
                                condition_met = actual_value is not None
                            else:
                                condition_met = actual_value == expected_value
                            
                            if negate:
                                condition_met = not condition_met

                            if not condition_met:
                                logger.info(
                                    f"【定义读取器】: 服务 '{member.__name__}' 未被加载 (因 @conditional_on_setting): "
                                    f"配置项 '{key}' 的值为 '{actual_value}', "
                                    f"期望条件 (expected: '{expected_value}', match_if_present: {match_if_present}, negate: {negate}) 未满足。"
                                )
                                all_conditions_met = False
                                break
                        
                        if not all_conditions_met:
                            continue

                    # 构建服务定义
                    service_name_override = getattr(member, '_axiom_service_name', None)
                    service_name = service_name_override or member.__name__.lower()

                    if service_name in definitions:
                        # 这是一个常见的场景，当同一个包通过不同的路径被扫描到时会发生。
                        # 使用 DEBUG 级别可以避免在正常运行时产生不必要的噪音。
                        logger.warning(f"【定义读取器】: 服务名称冲突，服务 '{service_name}' 已被注册，将忽略 '{module_name}.{member_name}'。")
                        continue
                    
                    definition = ServiceDefinition(
                        name=service_name,
                        target=member,
                        is_primary=getattr(member, '_axiom_is_primary', False),
                        provides=getattr(member, '_axiom_service_provides', None)
                    )
                    
                    definitions[service_name] = definition
                    logger.info(f"【定义读取器】: +++ 已成功注册服务定义: '{service_name}' (来自: {module_name}.{member_name})")
            except Exception as e:
                # [关键修复] 遵循 Fail-Fast 原则。任何模块加载失败都应立即中断应用启动。
                # 包装原始异常可以提供更丰富的上下文，同时保留原始的堆栈跟踪。
                logger.error(f"【定义读取器】: 加载模块 '{module_name}' 或读取其定义时发生严重错误: {e}", exc_info=True)
                raise FrameworkException(f"加载模块 '{module_name}' 失败，应用无法启动。请检查上面的详细错误信息。") from e
        
        logger.info(f"【定义读取器】: 定义读取完成，共找到 {len(definitions)} 个有效的服务定义。")
        return definitions 